/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.handlers.commands.call;

import android.media.MediaPlayer;

import com.hercules.android.receiver.AndroidReceiver;
import com.hercules.android.receiver.handlers.commands.XREObjectCommandHandler;
import com.hercules.android.receiver.handlers.events.EventRaiser;
import com.hercules.android.receiver.handlers.events.EventRaisingException;
import com.hercules.android.receiver.model.commands.XRECallCommand;
import com.hercules.android.receiver.model.commands.XRECommand;
import com.hercules.android.receiver.model.events.XREVideoStatusEvent;
import com.hercules.android.receiver.model.objects.XREVideo;

/**
 * This class represents the call command handler for a XREVideo object. It extends from XREObjectCommandHandler.
 * <p>
 * <b>Sample Usage:</b>
 *
 * <pre>
 * // create XREVideoCallCommandHandler instance
 * XREVideoCallCommandHandler handler = new XREVideoCallCommandHandler();
 *
 * // set required fields
 * handler.setEventRaiser(new MockEventRaiser());
 *
 * // prepare receiver
 * AndroidReceiver receiver = prepareAggregateReceiver(new XREVideo());
 *
 * // process play command to start playing
 * XRECallCommand command = prepareCommand(&quot;play&quot;);
 * handler.processCommandMessage(command, receiver);
 *
 * // process request status event to get video status
 * command = prepareCommand(&quot;requestStatus&quot;);
 * handler.processCommandMessage(command, receiver);
 *
 * // process pause command to pause playing
 * command = prepareCommand(&quot;pause&quot;);
 * handler.processCommandMessage(command, receiver);
 *
 * // process stop command to stop playing
 * command = prepareCommand(&quot;stop&quot;);
 * handler.processCommandMessage(command, receiver);
 * </pre>
 * <p>
 * <b>Thread Safety:</b> Not thread safe since it is mutable.
 *
 * @author DanLazar, orial
 * @version 1.0
 */
public class XREVideoCallCommandHandler extends XREObjectCommandHandler {
    /** Represents the name of video players. */
    private static final String VIDEO_PLAYERS_NAME = "videoPlayers";

    /**
     * The event raiser for {@link XREVideoStatusEvent} event.
     * <p>
     * It has getter and setter. Cannot be null after set. Is used in requestStatus method.
     */
    private EventRaiser eventRaiser;

    /**
     * Default empty constructor.
     */
    public XREVideoCallCommandHandler() {
        // empty
    }

    /**
     * Gets the event raiser for {@link XREVideoStatusEvent} event.
     *
     * @return the event raiser for {@link XREVideoStatusEvent} event
     */
    public EventRaiser getEventRaiser() {
        return eventRaiser;
    }

    /**
     * Sets the event raiser for {@link XREVideoStatusEvent} event.
     *
     * @param eventRaiser the event raiser for {@link XREVideoStatusEvent} event
     * @throws IllegalArgumentException if parameter is null
     */
    public void setEventRaiser(EventRaiser eventRaiser) {
        // check argument
        Helper.checkNotNull(eventRaiser, "eventRaiser");

        this.eventRaiser = eventRaiser;
    }

    /**
     * Process the given command.
     *
     * @param command the command
     * @param receiver the receiver
     * @throws IllegalArgumentException if any parameter is incorrect
     * @throws IllegalStateException if required field is not set or player is not found
     * @throws XREVideoCallCommandHandlerException if any error occurs while processing the command
     */
    @Override
    public void processCommandMessage(XRECommand command, AndroidReceiver receiver)
        throws XREVideoCallCommandHandlerException {
        String methodName = "processCommandMessage";
        Helper.logEnter(getLogger(), this, methodName, command, receiver);

        try {
            // check arguments and get target object
            XRECallCommand callCommand = Helper.checkCommand(command);
            XREVideo video = Helper.checkReceiver(receiver, callCommand, XREVideo.class);

            // get command method
            String method = callCommand.getMethod();

            // execute corresponding action
            if ("play".equals(method)) {
                play(receiver, video);
            } else if ("pause".equals(method)) {
                pause(receiver, video);
            } else if ("stop".equals(method)) {
                stop(receiver, video);
            } else if ("requestStatus".equals(method)) {
                requestStatus(receiver, video);
            } else {
                throw new XREVideoCallCommandHandlerException("Call command method '" + method + "' is not supported.");
            }

            Helper.logExit(getLogger(), this, methodName);
        } catch (IllegalArgumentException e) {
            Helper.logError(getLogger(), e, methodName, e);
        } catch (IllegalStateException e) {
            Helper.logError(getLogger(), e, methodName, e);
        } catch (XREVideoCallCommandHandlerException e) {
            Helper.logError(getLogger(), e, methodName, e);
        }
    }

    /**
     * This method will start playing the video file from the beginning if video file is not paused or resume playing
     * the video file if video file is paused.
     *
     * @param receiver the receiver
     * @param video the xre video object
     * @throws IllegalArgumentException if receiver is not correct
     * @throws IllegalStateException if player is not found
     * @throws XREVideoCallCommandHandlerException if any other error occurs
     */
    private static void play(AndroidReceiver receiver, XREVideo video) throws XREVideoCallCommandHandlerException {
        try {
            // get player
            MediaPlayer player = Helper.getMediaPlayer(receiver, VIDEO_PLAYERS_NAME, video.getId());

            // start player
            player.start();
        } catch (IllegalStateException e) {
            throw new XREVideoCallCommandHandlerException("Player is in not valid state.", e);
        }
    }

    /**
     * This method will pause the video file.
     *
     * @param receiver the receiver
     * @param video the xre video object
     * @throws IllegalArgumentException if receiver is not correct
     * @throws IllegalStateException if player is not found
     * @throws XREVideoCallCommandHandlerException if any other error occurs
     */
    private static void pause(AndroidReceiver receiver, XREVideo video) throws XREVideoCallCommandHandlerException {
        try {
            // get player
            MediaPlayer player = Helper.getMediaPlayer(receiver, VIDEO_PLAYERS_NAME, video.getId());

            // pause player
            player.pause();
        } catch (IllegalStateException e) {
            throw new XREVideoCallCommandHandlerException("Player is in not valid state.", e);
        }
    }

    /**
     * This method will stop the video file.
     *
     * @param receiver the receiver
     * @param video the xre video object
     * @throws IllegalArgumentException if receiver is not correct
     * @throws IllegalStateException if player is not found
     * @throws XREVideoCallCommandHandlerException if any other error occurs
     */
    private static void stop(AndroidReceiver receiver, XREVideo video) throws XREVideoCallCommandHandlerException {
        try {
            // get player
            MediaPlayer player = Helper.getMediaPlayer(receiver, VIDEO_PLAYERS_NAME, video.getId());

            // stop player
            player.stop();
        } catch (IllegalStateException e) {
            throw new XREVideoCallCommandHandlerException("Player is in not valid state.", e);
        }
    }

    /**
     * This method instructs the receiver to raise a onVideoStatus event that provides additional information about the
     * video.
     *
     * @param receiver the receiver
     * @param video the xre video object
     * @throws IllegalStateException if eventRaiser field is not set
     * @throws XREVideoCallCommandHandlerException if any other error occurs
     */
    private void requestStatus(AndroidReceiver receiver, XREVideo video) throws XREVideoCallCommandHandlerException {
        // check state
        Helper.checkState(eventRaiser, "eventRaiser");

        try {
            // prepare the event
            XREVideoStatusEvent event = new XREVideoStatusEvent();
            event.setName(XREVideoStatusEvent.ON_VIDEO_STATUS_EVENT_NAME);
            event.setConnectionURL(video.getUrl());
            event.setPosition(video.getPosition());
            event.setSource(video.getId());

            // raise event
            eventRaiser.raiseEvent(event, receiver, false);
        } catch (EventRaisingException e) {
            throw new XREVideoCallCommandHandlerException("Error occurred while raising 'onVideoStatus' event.", e);
        }
    }
}